﻿using CrmCustomizationsExcelAddIn.Data;
using CrmCustomizationsExcelAddIn.Data.Fetchxml;
using CrmCustomizationsExcelAddIn.Data.FormXml;
using Microsoft.Office.Interop.Excel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CrmCustomizationsExcelAddIn.Helper
{
    public class GlobalOperations
    {
        public static void LoadOperations()
        {
            IEnumerable<EntityMetadata> entitieslist = Globals.CrmAddIn.crmOpHelper.RetriveAllEntities();
            GlobalApplicationData.Instance.optionSetData = Globals.CrmAddIn.crmOpHelper.retrieveAllGlobalOptionSets();
            GlobalApplicationData.Instance.crmInstalledLanguages = Globals.CrmAddIn.crmOpHelper.installedLanguages();
            GlobalApplicationData.Instance.crmPubblishers = Globals.CrmAddIn.crmOpHelper.GetPublishersList();
            GlobalApplicationData.Instance.currentLanguage = GlobalApplicationData.Instance.crmInstalledLanguages.FirstOrDefault();
            GlobalApplicationData.Instance.crmSolutions = Globals.CrmAddIn.crmOpHelper.getAllSolution();
            GlobalApplicationData.Instance.allEntities = entitieslist.OrderBy(p => Utils.getLocalizedLabel(p.DisplayName.LocalizedLabels, GlobalApplicationData.Instance.currentLanguage)).ToArray();
            Solution solution = GlobalApplicationData.Instance.crmSolutions.Where(x => x.SolutionName.Equals("Default", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
            string DeafultSolution = solution != null ? solution.SolutionName : GlobalApplicationData.Instance.crmSolutions.First().SolutionName;
            GlobalApplicationData.Instance.currentSolution = solution ?? GlobalApplicationData.Instance.crmSolutions.First();
            FilterBySolution(DeafultSolution);
        }

        public static void FilterBySolution(string solutionName)
        {
            Solution solution = GlobalApplicationData.Instance.crmSolutions.Where(x => x.SolutionName.Equals(solutionName)).FirstOrDefault();
            IEnumerable<Guid> solutionlist = Globals.CrmAddIn.crmOpHelper.getAllSolutionEntities(solution.SolutionId);
            GlobalApplicationData.Instance.currentEnitiesList = GlobalApplicationData.Instance.allEntities.Join(solutionlist, x => x.MetadataId, y => y, (x, y) => x).ToArray();
            GlobalApplicationData.Instance.currentSolution = solution ?? GlobalApplicationData.Instance.crmSolutions.First();
        }


        public static string getCurrentSolutionPubblisher(GlobalApplicationData appData)
        {
            Publisher p = appData.crmPubblishers.Where(x => appData.currentSolution.PubblisherId == x.PublisherId).SingleOrDefault();
            return p != null ? p.CustomizationPrefix : appData.crmPubblishers.First().CustomizationPrefix;
        }




        public static void RefreshCurrentFormSheet()
        {
            GlobalApplicationData data = GlobalApplicationData.Instance;
            if (data.eSheetsInfomation.getCurrentSheet().sheetType == ExcelSheetInfo.ExcelSheetType.form)
            {
                Entity form = Globals.CrmAddIn.crmOpHelper.GetForm(Guid.Parse(data.eSheetsInfomation.getCurrentSheet().objectName));
                if (form != null && form.Contains("name") && form.Contains("formxml") && form.Contains("objecttypecode"))
                {
                    string sheetName = string.Format("{0} - {1}", form["name"].ToString(), form["objecttypecode"].ToString());
                    FormType formObj = FormXmlMapper.MapFormXmlToObj(form.Attributes["formxml"].ToString());
                    data.eSheetsInfomation.getCurrentSheet().language = GlobalApplicationData.Instance.currentLanguage;
                    Globals.CrmAddIn.excelHelper.RefreshFormSheet(data.eSheetsInfomation.getCurrentSheet());
                }
            }
        }


        public static void CreatenNewAttributesSheet(Guid entityId)
        {
            GlobalApplicationData data = GlobalApplicationData.Instance;
            EntityMetadata currentEntity = Globals.CrmAddIn.crmOpHelper.RetriveEntityAtrribute(entityId);
            string sheetName = Utils.getLocalizedLabel(currentEntity.DisplayName.LocalizedLabels, data.currentLanguage);
            AttributeExcelSheetsInfo attributesSheet = new AttributeExcelSheetsInfo(currentEntity, GlobalOperations.getCurrentSolutionPubblisher(data));
            CreatenNewExcelSheet(sheetName, attributesSheet);
            IEnumerable<string> formAttr = Globals.CrmAddIn.crmOpHelper.GetAttributeOfTheMainForm(currentEntity.ObjectTypeCode.Value);
            Globals.CrmAddIn.excelHelper.refreshAttributeSheeet(data.eSheetsInfomation.getCurrentSheet(), currentEntity, GlobalApplicationData.Instance.allEntities, formAttr);
        }

        public static void CreatenNewFormSheet(Guid formId)
        {
            Entity form = Globals.CrmAddIn.crmOpHelper.GetForm(formId);
            if (form != null && form.Contains("name") && form.Contains("formxml") && form.Contains("objecttypecode"))
            {
                GlobalApplicationData data = GlobalApplicationData.Instance;
                string sheetName = string.Format("{0} - {1}", form["name"].ToString(), form["objecttypecode"].ToString());
                FormType formObj = FormXmlMapper.MapFormXmlToObj(form.Attributes["formxml"].ToString());
                CreatenNewExcelSheet(sheetName, new FormExcelSheetsInfo(formId, form.Attributes["formxml"].ToString(), formObj));
                data.eSheetsInfomation.getCurrentSheet().language = GlobalApplicationData.Instance.currentLanguage;
                Globals.CrmAddIn.excelHelper.RefreshFormSheet(data.eSheetsInfomation.getCurrentSheet());
            }
        }

        public static void CreatenNewViewSheet(Guid viewId, Guid entity)
        {
            Entity view = Globals.CrmAddIn.crmOpHelper.GetView(viewId);
            EntityMetadata etMetadata = Globals.CrmAddIn.crmOpHelper.RetriveEntityAtrribute(entity);
            IEnumerable<AttributeMetadata> attr = etMetadata.Attributes.Where(x => x.AttributeType != null && x.AttributeType == AttributeTypeCode.Lookup);
            if (view != null && view.Contains("name") && view.Contains("layoutxml") && view.Contains("returnedtypecode") && view.Contains("fetchxml"))
            {
                GlobalApplicationData data = GlobalApplicationData.Instance;
                string sheetName = string.Format("{0} - {1}", view["name"].ToString(), view["returnedtypecode"].ToString());
                savedqueryLayoutxmlGrid viewObj = FormXmlMapper.MapViewXmlToObj(view.Attributes["layoutxml"].ToString());
                FetchType fatchObj = FormXmlMapper.MapFetchXmlToObj(view.Attributes["fetchxml"].ToString());
                CreatenNewExcelSheet(sheetName, new ViewExcelSheetsInfo(viewId, view.Attributes["layoutxml"].ToString(), view.Attributes["fetchxml"].ToString(), viewObj, fatchObj, entity, etMetadata.LogicalName));
                ViewExcelSheetsInfo currentSheet = ((ViewExcelSheetsInfo)data.eSheetsInfomation.getCurrentSheet());
                currentSheet.language = GlobalApplicationData.Instance.currentLanguage;
                currentSheet.relationsList = ViewXml.GenerateViewRelatedObj(currentSheet);
                Globals.CrmAddIn.excelHelper.RefreshViewSheet(data.eSheetsInfomation.getCurrentSheet(), attr);
            }
        }



        public static void CreatenNewViewSheet(string viewName, string viewDescription, Guid entity)
        {
            EntityMetadata etMetadata = Globals.CrmAddIn.crmOpHelper.RetriveEntityAtrribute(entity);
            IEnumerable<AttributeMetadata> attr = etMetadata.Attributes.Where(x => x.AttributeType != null && x.AttributeType == AttributeTypeCode.Lookup);
            GlobalApplicationData data = GlobalApplicationData.Instance;
            string sheetName = string.Format("{0} - {1}", viewName, etMetadata.LogicalName.ToString());
            CreatenNewExcelSheet(sheetName, new ViewExcelSheetsInfo(Guid.NewGuid(), viewName, viewDescription, etMetadata.LogicalName,entity));
            ViewXml.GenerateNewFechXml((ViewExcelSheetsInfo)data.eSheetsInfomation.getCurrentSheet(), etMetadata);
            ViewExcelSheetsInfo currentSheet = ((ViewExcelSheetsInfo)data.eSheetsInfomation.getCurrentSheet());
            currentSheet.language = GlobalApplicationData.Instance.currentLanguage;
            currentSheet.relationsList = ViewXml.GenerateViewRelatedObj(currentSheet);
            Globals.CrmAddIn.excelHelper.RefreshViewSheet(data.eSheetsInfomation.getCurrentSheet(), attr);
        }


        public static void RefreshCurrentViewSheet()
        {
            ViewExcelSheetsInfo currentSheet = ((ViewExcelSheetsInfo)GlobalApplicationData.Instance.eSheetsInfomation.getCurrentSheet());
            Entity view = Globals.CrmAddIn.crmOpHelper.GetView(currentSheet.viewId);
            EntityMetadata etMetadata = Globals.CrmAddIn.crmOpHelper.RetriveEntityAtrribute(currentSheet.enitityid);
            IEnumerable<AttributeMetadata> attr = etMetadata.Attributes.Where(x => x.AttributeType != null && x.AttributeType == AttributeTypeCode.Lookup);
            if (view != null && view.Contains("name") && view.Contains("layoutxml") && view.Contains("returnedtypecode") && view.Contains("fetchxml"))
            {
                GlobalApplicationData data = GlobalApplicationData.Instance;
                string sheetName = string.Format("{0} - {1}", view["name"].ToString(), view["returnedtypecode"].ToString());
                savedqueryLayoutxmlGrid viewObj = FormXmlMapper.MapViewXmlToObj(view.Attributes["layoutxml"].ToString());
                FetchType fatchObj = FormXmlMapper.MapFetchXmlToObj(view.Attributes["fetchxml"].ToString());
                currentSheet.layoutXml = view.Attributes["layoutxml"].ToString();
                currentSheet.fetchxml = view.Attributes["fetchxml"].ToString();
                currentSheet.viewObj = viewObj;
                currentSheet.fetchObj = fatchObj;
                currentSheet.language = GlobalApplicationData.Instance.currentLanguage;
                currentSheet.relationsList = ViewXml.GenerateViewRelatedObj(currentSheet);
                Globals.CrmAddIn.excelHelper.RefreshViewSheet(data.eSheetsInfomation.getCurrentSheet(), attr);
            }
        }

        public static EntityMetadata[] getEntitiesWithAttributes()
        {
            EntityMetadata[] allEntities = new EntityMetadata[GlobalApplicationData.Instance.currentEnitiesList.Count()];
            int index = 0;
            foreach (var entity in GlobalApplicationData.Instance.currentEnitiesList)
            {
                if (entity.MetadataId != null)
                {
                    EntityMetadata ent = Globals.CrmAddIn.crmOpHelper.RetriveEntityAtrribute(entity.MetadataId.Value);
                    if (ent != null)
                    {
                        allEntities[index] = ent;
                        index++;
                    }
                }
            }

            return allEntities;
        }

        public static void CreatenNewEntitySheet()
        {
            GlobalApplicationData data = GlobalApplicationData.Instance;
            string sheetName = string.Format("Entities List - {0}", data.currentSolution.SolutionName);
            EntityMetadata[] allEntities = getEntitiesWithAttributes();
            EntityExcelSheetsInfo excelSheet = new EntityExcelSheetsInfo(ExcelSheetInfo.ExcelSheetType.entity, allEntities, sheetName);
            CreatenNewExcelSheet(sheetName, excelSheet);
            Globals.CrmAddIn.excelHelper.refreshEntitySheeet(data.eSheetsInfomation.getCurrentSheet(), allEntities);
        }

        public static void CreatenNewOptionSetSheet(OptionSetMetadata optionSetMetadata, AttributeMetadata currentAttribute)
        {
            GlobalApplicationData appData = GlobalApplicationData.Instance;
            string sheetName = optionSetMetadata.MetadataId.ToString();
            OptionSetExcelSheetsInfo excelSheet = new OptionSetExcelSheetsInfo(ExcelSheetInfo.ExcelSheetType.optionSet, optionSetMetadata, currentAttribute);
            CreatenNewExcelSheet(sheetName, excelSheet);
            Globals.CrmAddIn.excelHelper.refreshOptionSetSheet(GlobalApplicationData.Instance.eSheetsInfomation.getCurrentSheet());
        }

        public static void CreatenNewExcelSheet(string sheetName, ExcelSheetInfo excelInfo)
        {
            GlobalApplicationData data = GlobalApplicationData.Instance;
            bool sheetRemoved = false;
            ExcelSheetInfo currentSheet = data.eSheetsInfomation.getSheetByName(excelInfo.objectName);
            if (currentSheet != null)
            {
                data.eSheetsInfomation.setCurrentSheet(excelInfo.objectName);
                sheetRemoved = Globals.CrmAddIn.excelHelper.selectSheet(currentSheet.workSheetName, data.eSheetsInfomation.getCurrentSheet());
            }
            if (sheetRemoved)
            {
                data.eSheetsInfomation.removeSheetByName(excelInfo.objectName);
            }
            if (data.eSheetsInfomation.getSheetByName(excelInfo.objectName) == null || sheetRemoved)
            {
                string excelName = GetValidWorksheetName(sheetName != string.Empty ? sheetName : excelInfo.objectName);
                Worksheet sheet = Globals.CrmAddIn.excelHelper.createNewWorksheet(excelName);
                excelInfo.excelsheet = sheet;
                excelInfo.workSheetName = excelName;
                data.eSheetsInfomation.addSheetAndSetAsCurrent(excelInfo, excelInfo.objectName);
            }
        }

        private static string GetValidWorksheetName(string name)
        {
            // Worksheet name cannot be longer than 31 characters.
            StringBuilder escapedString;
            if (name.Length <= 31)
            {
                escapedString = new StringBuilder(name);
            }
            else
            {
                escapedString = new StringBuilder(name, 0, 31, 31);
            }
            for (int i = 0; i < escapedString.Length; i++)
            {

                if (escapedString[i] == ':' || escapedString[i] == '\\' || escapedString[i] == '/' || escapedString[i] == '?' || escapedString[i] == '*' || escapedString[i] == '[' || escapedString[i] == ']')
                {
                    escapedString[i] = '_';
                }

            }
            return escapedString.ToString();
        }


    }
}
